/* -----------------------------------------------------------------------
 * Include the following lines in your makefile:
 *
 * unittest1: randomtestcard.c dominion.o rngs.o
 *      gcc -o randomtestcard -g  randomtestcard.c dominion.o rngs.o $(CFLAGS)
 * -----------------------------------------------------------------------
 */

#include "dominion.h"
#include "dominion_helpers.h"
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "rngs.h"
#include <time.h>
#include <stdlib.h>
#include <math.h>

// set NOISY_TEST to 0 to remove printfs from output
#define NOISY_TEST 1
#define PRINT_CARD_PILES 1
#define PLAY_CARD remodel
#define PLAY_CARD_STR "remodel"
#define PLAY_CARDS 27
#define MAX_TESTS 500

//set ASSERTIONS_ON to 1 to use assertions
#define ASSERTIONS_ON 0

int main() {
    int i, r, tcCount = 0;
    int handCount, deckCount, discardCount;
    int handPos = 0, choice1 = 0, choice2 = 0, choice3 = 0;
    int choice1Cost = 0, choice2Cost = 0;
    int hasPlayCard = 0, canTrash = 1, canBuy = 1;
    int handChange = 0, discardChange = 0;
    int numPlayer = 2;
    int seed = 1000;
    int k[10] = {adventurer, council_room, feast, gardens, mine
               ,remodel, smithy, village, baron, great_hall};
    int maxHandCount = 5;
    int maxDeckCount = 10;
    int maxDiscardCount = 10;
    int player_hand[maxHandCount];
    int player_deck[maxDeckCount];
    int player_discard[maxDeckCount];
    int preDeckCount, preHandCount, preDiscardCount;
    int postDeckCount, postHandCount, postDiscardCount;

    struct gameState G;
    
    char *cardNames[] = 
	  {"curse", "estate", "duchy", "province", "copper", "silver", "gold", "adventurer", "council_room", "feast", "gardens", "mine", "remodel", "smithy", "village", "baron", "great_hall", "minion", "steward", "tribute", "ambassador", "cutpurse", "embargo", "outpost", "salvager", "sea_hag", "treasure_map" };

	srand(time(NULL));

#if (NOISY_TEST == 1)    		
    printf ("RANDOM TESTING %s card:\n", PLAY_CARD_STR);	
#endif

	while(tcCount < MAX_TESTS)
    {
    	handCount = rand() % (maxHandCount + 1); //added 1 to go from 0 to maxHandCount
    	deckCount = rand() % (maxDeckCount + 1); //added 1 to go from 0 to maxDeckCount
    	discardCount = rand() % (maxDiscardCount + 1); //added 1 to go from 0 to maxDiscardCount
    	hasPlayCard = 0;
    	canTrash = 1;
    	canBuy = 1;
    	handChange = 0;
    	discardChange = 0;
    
		memset(&G, 23, sizeof(struct gameState));   // clear the game state
	    r = initializeGame(numPlayer, k, seed, &G); // initialize a new game
	    
	    /* Fill up the player's hand, deck, and discard piles with random cards. */
	    for (i = 0; i < handCount; i++){
	    	player_hand[i] = rand() % PLAY_CARDS;
	    	if (!hasPlayCard)
	    		if (player_hand[i] == PLAY_CARD) {
	    			hasPlayCard = 1;
	    			handPos = i;
	    		}
	    }

	    for (i = 0; i < deckCount; i++){
	    	player_deck[i] = rand() % PLAY_CARDS;
	    }
	    
	    for (i = 0; i < discardCount; i++){
	    	player_discard[i] = rand() % PLAY_CARDS;
	    }
	    
	    /* Set choice1 to a card in player's hand.
	    	If handCount is 0, set choice1 to zero to avoid DIV/0 error*/
	    // choice1 is the card to trash
	    choice1 = (handCount == 0 ? 0 : rand() % handCount);
	    choice1Cost = getCost(player_hand[choice1]);
	    
	    // Set choice2 to a random card
	    // choice2 is the card to gain
	    choice2 = rand() % PLAY_CARDS;
	    choice2Cost = getCost(choice2);
	    
	    /* Is choice1 the remodel card to play? In which case, it can't be trashed. */
	    if (choice1 == handPos)
	    	canTrash = 0;
	    
	    /* Is choice2 used in the game? */
	    if (supplyCount(choice2, &G) > 0 ){
		    /*Is choice2 cost more than 2 coins greater than choice1 cost?*/
	    	if (choice1Cost < choice2Cost - 2)
	    		canBuy = 0;
	    }
	    else
	    	canBuy = 0;
	    
	    if (canTrash && canBuy){
		    /* Should the player still have the remodel card in hand after playing it? 
		    Or should it be moved into the discard pile?
		    The card seems to disappear...*/
	    	handChange = -1; 
	    	discardChange = 1;
	    }
	    
		G.handCount[0] = handCount;                 // set the number of cards on hand
		G.deckCount[0] = deckCount;					// set the number of cards in the deck
		G.discardCount[0] = discardCount;			// set the number of cards in the discard pile
		
		memcpy(G.hand[0], player_hand, sizeof(int) * handCount); // set all the cards to player_hand
		memcpy(G.deck[0], player_deck, sizeof(int) * deckCount); // set all the cards to player_deck
		memcpy(G.discard[0], player_discard, sizeof(int) * discardCount); // set all the cards to player_discard
		
		// these values should still match what we set them to
		preHandCount = G.handCount[0];				
		preDeckCount = G.deckCount[0];				
		preDiscardCount = G.discardCount[0];
		
		if (hasPlayCard){
#if (NOISY_TEST == 1)
			printf("--------------------------------------------------------------------------------------------\n");
			printf("Iteration %d: Hand Count = %d, Deck Count = %d, Discard Count = %d\n", tcCount, handCount, deckCount, discardCount);
			printf("Playing %s\n", PLAY_CARD_STR);
			printf("Card to trash is %s with a cost of %d.\n", cardNames[player_hand[choice1]], choice1Cost);
			printf("Card can%s be trashed.\n", (canTrash ? "" : "'t"));  
			printf("Card to gain is %s with a cost of %d.\n", cardNames[choice2], choice2Cost);
			printf("Card can%s be gained.\n", (canBuy ? "" : "'t"));
#endif

#if (PRINT_CARD_PILES == 1)
			for (i = 0; i < preHandCount; i++)
				printf("Hand position %d, card %s\n", i, cardNames[G.hand[0][i]]);
			/*for (i = 0; i < preDeckCount; i++)
				printf("Deck position %d, card %s\n", i, cardNames[G.deck[0][i]]);*/
			for (i = 0; i < preDiscardCount; i++)
				printf("Discard position %d, card %s\n", i, cardNames[G.discard[0][i]]);			
#endif
				
			// play the card		
			r = playCard(handPos,choice1,choice2,choice3,&G);

#if (NOISY_TEST == 1)
			printf("Card played.\n");
#endif
			/* Get the card pile counts after the card was played
			and cards were possibly shuffled. */
			postHandCount = G.handCount[0];
			postDeckCount = G.deckCount[0];
			postDiscardCount = G.discardCount[0];
			
#if (PRINT_CARD_PILES == 1)
			for (i = 0; i < postHandCount; i++)
				printf("Hand position %d, card %s\n", i, cardNames[G.hand[0][i]]);
			/*for (i = 0; i < postDeckCount; i++)
				printf("Deck position %d, card %s\n", i, cardNames[G.deck[0][i]]);*/
			for (i = 0; i < postDiscardCount; i++)
				printf("Discard position %d, card %s\n", i, cardNames[G.discard[0][i]]);			
#endif

#if (ASSERTIONS_ON == 1)
			assert(postHandCount >= 0);
			/*assert(postDeckCount >= 0);*/
			assert(postDiscardCount >= 0);
			assert(postHandCount == handCount + handChange);
			assert(postDiscardCount == discardCount + discardChange);
#endif	
			
#if (NOISY_TEST == 1)
		    printf("Pre hand count = %d, Post hand count = %d, expected = %d.\n", preHandCount, postHandCount, handCount + handChange);
		    /*printf("Pre deck count = %d, Post deck count = %d, expected = %d.\n", preDeckCount, postDeckCount, deckCount);*/
		    printf("Pre discard count = %d, Post discard count = %d, expected = %d.\n", preDiscardCount, postDiscardCount, discardCount + discardChange);
#endif	

		}
		tcCount++;
		
	}
    
#if (ASSERTIONS_ON == 1)
    printf("\nAll domain tests passed!\n");
#endif	
#if (ASSERTIONS_ON == 0)
    printf("\nTests were run without assetions.\n");
#endif	

        
    return 0;
}
